package cn.hbu.zlfw.exchange.websocket;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.hbu.zlfw.common.util.SessionUtil;
import cn.hbu.zlfw.common.util.Utility;
import cn.hbu.zlfw.exchange.entity.Chat;
import cn.hbu.zlfw.exchange.service.ChatService;
import cn.hbu.zlfw.patent.service.PatentService;


import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 
 * @ClassName: WSServer
 * @Description: 在线聊天的websocket server
 * @author tiddar
 * @date 2018年8月13日
 *
 */
@Controller
@ServerEndpoint(value = "/chat.action/{patentId}", configurator = ChatConfigurator.class)
public class WSServer extends TextWebSocketHandler {

	public final Logger logger = LoggerFactory.getLogger(WSServer.class);

	// 在线人数 线程安全
	private static int onlineCount = 0;

	// 连接集合 userId => server 键值对 线程安全
    private static final Map<String, Set<Session>> rooms = new ConcurrentHashMap();

	// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private Session session;

	// 当前会话的httpsession
	private HttpSession httpSession;
	private ChatService chatService = (ChatService) ContextLoader.getCurrentWebApplicationContext()
			.getBean("chatService");
	private PatentService patentService = (PatentService) ContextLoader.getCurrentWebApplicationContext()
			.getBean("patentService");
	private static ObjectMapper mapper = new ObjectMapper();
	public WSServer() {
	}

	/**
	 * @param session websocket连接sesson
	 * @param config  {@link com.github.websocket.configuration.HttpSessionConfigurator}
	 * @DESC
	 *       <p>
	 *       注解{@link OnOpen} 声明客户端连接进入的方法
	 *       </p>
	 */
	@OnOpen
	public void onOpen(@PathParam("patentId") String patentId,Session session, EndpointConfig config) {

		this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

		//将session按照房间名来存储，将各个房间的用户隔离
        if (!rooms.containsKey(patentId)) {
            // 创建房间不存在时，创建房间
            Set<Session> room = new HashSet<>();
            // 添加用户
            room.add(session);
            rooms.put(patentId, room);
        } else {
            // 房间已存在，直接添加用户到相应的房间
            rooms.get(patentId).add(session);
        }

		addOnlineCount();
		logger.info("有新的用户交流连接，当前连接数为：" + getOnlineCount());

	}

	/**
	 * <p>
	 * {@link OnClose} 关闭连接
	 * </p>
	 */
	@OnClose
	public void onClose(@PathParam("patentId") String patentId, Session session) {

        rooms.get(patentId).remove(session);

		logger.info("有一连接断开，当前连接数为：" + getOnlineCount());
	}

	/**
	 * <p>
	 * {@link OnMessage} 消息监听处理方法
	 * </p>
	 *
	 * @param message 消息对象{@link com.github.websocket.msg.Msg}的JSON对象
	 * @throws IOException 异常
	 */
	@OnMessage
	public void onMessage(@PathParam("patentId") String patentId,String message) throws IOException {

		System.out.println("捕捉消息发送");
		// 将消息转Msg对象

		Chat msg = mapper.readValue(message,Chat.class);

		// TODO 可以对msg做些处理...
		// 根据Msg消息对象获取定点发送人的userId
		Set<Session> forPatentServer = rooms.get(patentId);

		for(Session ses : forPatentServer) {
			// 消息发送
			msg.setCreateTime(new Date());
			msg.setUpdateTime(new Date());
			msg.setDelState(0);
			msg.setPatent(patentService.getById(msg.getPatentId()));
			msg.setUser(httpSession.getAttribute("user"));
			ses.getBasicRemote().sendText(mapper.writeValueAsString(msg));
			chatService.save(msg);
		}

	}

	/**
	 * <p>
	 * {@link OnError} websocket系统异常处理
	 * </p>
	 *
	 * @param t 异常
	 */
	@OnError
	public void onError(Throwable t) {
		logger.error(t.toString());
		t.printStackTrace();
	}


	// 获取连接数
	private static synchronized int getOnlineCount() {
		return WSServer.onlineCount;
	}

	// 增加连接数
	private static synchronized void addOnlineCount() {
		WSServer.onlineCount++;
	}

	// 减少连接数
	private static synchronized void subOnlineCount() {
		WSServer.onlineCount--;
	}

}